using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using usm.SolDev.DataBase.DataObjects;
using usm.SolDev.DataBase.DataAccess;
using usm.SolDev.Common;
using System.Runtime.Remoting.Messaging;
using usm.SolDev.Common.Constants;
using WeifenLuo.WinFormsUI.Docking;

namespace usm.SolDev.UI.Db
{
    public partial class RepositoryExplorer : ToolWindow
    {
        #region Open project delegate
        public delegate void OpenProjectDelegate(object sender, ProjectDescriptor projectDescriptor);
        public event OpenProjectDelegate OpenProject;
        #endregion

        #region View results delegate
        public delegate void ViewResultsDelegate(object sender, ProjectDescriptor projectDescriptor);
        public event ViewResultsDelegate ViewResultsProject;
        #endregion

        #region View tabular results delegate
        public delegate void ViewTabularResultsDelegate(object sender, ProjectDescriptor projectDescriptor);
        public event ViewTabularResultsDelegate ViewTabularResultsProject;
        #endregion

        #region Delete project delegate
        public delegate void NotifyDeleteProjectDelegate(object sender, string projectId);
        public event NotifyDeleteProjectDelegate DeleteProjectNotify;
        #endregion

        #region Constructors
        /// <summary>
        ///     Default constructor
        /// </summary>
        public RepositoryExplorer()
        {
            InitializeComponent();
        }
        #endregion

        #region Delegates declaration and implementation
        /// <summary>
        ///     Load repository 
        /// </summary>
        /// <param name="userInfoData"></param>
        /// <returns></returns>
        private delegate List<ProjectDescriptor> LoadRepositoryContentDelegate(UserInfoData userInfoData);

        /// <summary>
        ///     Load repository content from database. The Repository is loaded 
        /// depending on the system settings (administrator's wishes). This form 
        /// can display only user's programs ... or the entire group.
        /// </summary>
        /// <param name="ar"></param>
        private void LoadRepositoryContentCallBack (IAsyncResult ar)
        {
            try
            {
                List<ProjectDescriptor> availableProjects = ((LoadRepositoryContentDelegate)((AsyncResult)ar).AsyncDelegate).EndInvoke(ar);

                if (!IsDisposed && IsHandleCreated)
                {
                    BeginInvoke(new AfterOperationCompletedDelegate(AfterOperationCompleted), new object[] { true, availableProjects });
                }
            }
            catch (Exception ex)
            {
                BeginInvoke(new AfterOperationCompletedDelegate(AfterOperationCompleted), new object[] { false, null });
                new SolDevException("Cannot complete load process", ex);
            }
        }

        /// <summary>
        ///     The operation complete call back. Is used to update visual components.
        /// </summary>
        /// <param name="success"></param>
        /// <param name="availableProjects"></param>
        private delegate void AfterOperationCompletedDelegate (bool success, List<ProjectDescriptor> availableProjects);
        private void AfterOperationCompleted(bool success, List<ProjectDescriptor> availableProjects)
        {
            propertyGrid1.SelectedObject = null;

            if (success == true)
            {
                if (availableProjects != null)
                {
                    dgvRepository.DataSource = availableProjects;
                    SetDatGridViewLayout(dgvRepository, new string[] { "Description", "UserName" });
                }
                else                {
                    new SolDevException("The repository data is not available");
                }
            }
        }
        #endregion

        #region Form events handlers
        /// <summary>
        ///     List all repository data associated with this user
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RepositoryExplorer_Load(object sender, EventArgs e)
        {
            (new LoadRepositoryContentDelegate(DataProvider.DataBase.LoadRepositoryContent)).BeginInvoke(WorksessionData.UserInfo, new AsyncCallback(LoadRepositoryContentCallBack), null);
        }

        /// <summary>
        ///     Setup grid layout. Show only selected columns and reorder them
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="columnNames"></param>
        protected static void SetDatGridViewLayout(DataGridView dataGridView, string [] columnNames)
        {
            #region Validate parameters
            if (dataGridView == null || columnNames == null )
            {
                throw new ArgumentNullException("dataGridView or columnNames parameter is null");
            }
            #endregion

            #region Show selected columns and set they order
            for ( int i = 0; i < dataGridView.Columns.Count; i ++)
            {
                dataGridView.Columns[i].Visible = false;
                for( int columnIndex = 0; columnIndex < columnNames.Length; columnIndex ++ )
                {
                    if (columnNames[columnIndex].ToUpper().Equals(dataGridView.Columns[i].Name.ToUpper()))
                    {
                        dataGridView.Columns[i].Visible = true;
                        dataGridView.Columns[i].DisplayIndex = columnIndex;
                    }
                }
            }
            #endregion
        }

        /// <summary>
        ///     Preview program code
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvRepository_SelectionChanged(object sender, EventArgs e)
        {
            try
            {
                ProjectDescriptor selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];
                propertyGrid1.SelectedObject = selectedProject;
            }
            catch
            {
                propertyGrid1.SelectedObject = null;
            }
            
        }

        /// <summary>
        ///     Handle double click event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnOpenProject(object sender, EventArgs e)
        {
            if (OpenProject != null )
            {
                ProjectDescriptor selectedProject = null;
                try
                {
                    selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];
                } catch {}
                
                if (selectedProject != null)
                {
                    OpenProject(sender, selectedProject);
                }
            }
        }

        /// <summary>
        ///     The DB context menu handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbMenuItemClick(object sender, EventArgs e)
        {
            #region Open project
            if (sender == menuItemOpen)
            {
                if (OpenProject != null && (dgvRepository.CurrentRow.Index > -1))
                {
                    ProjectDescriptor selectedProject = null;
                    try
                    {
                        selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];
                    }
                    catch { }

                    if (selectedProject != null)
                    {
                        OpenProject(sender, selectedProject);
                    }
                }

            }
            #endregion
            #region Delete project
            else if (sender == menuItemDelete && (dgvRepository.CurrentRow.Index > -1))
            {
                ProjectDescriptor selectedProject = null;
                selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];

                if (selectedProject != null)
                {
                    if(MessageBox.Show(String.Format("Sure to delete project {0} ?",selectedProject.Description) , "Confirm", MessageBoxButtons.YesNo ) == DialogResult.Yes)
                    {
                        (new DeleteProjectDelegate(DataProvider.DataBase.DeleteProjectFromRepository)).BeginInvoke(selectedProject, WorksessionData.UserInfo, new AsyncCallback(DeleteProjectCallBack), null);
                    }
                }
            }
            #endregion
            #region View experiment results in graphical mode
            else if (sender == menuItemViewResults)
            {
                if (ViewResultsProject != null && (dgvRepository.CurrentRow.Index > -1))
                {
                    ProjectDescriptor selectedProject = null;
                    try
                    {
                        selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];
                    }
                    catch { }

                    if (selectedProject != null && selectedProject.Results != null && selectedProject.Results.Equals(String.Empty) == false)
                    {
                        ViewResultsProject(sender, selectedProject);
                    }
                }
            }
            #endregion
            #region View experiment results in tabular mode
            else if (sender == menuItemViewTabularResults )
            {
                if (ViewTabularResultsProject != null && (dgvRepository.CurrentRow.Index > -1))
                {
                    ProjectDescriptor selectedProject = null;
                    try
                    {
                        selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];
                    }
                    catch { }

                    if (selectedProject != null && selectedProject.Results != null && selectedProject.Results.Equals(String.Empty) == false)
                    {
                        ViewTabularResultsProject(sender, selectedProject);
                    }
                }
            }
            #endregion
        }

        /// <summary>
        ///     Disable view results if no results are present
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbContextMenu_Opening(object sender, CancelEventArgs e)
        {
            ProjectDescriptor selectedProject = null;
            selectedProject = ((List<ProjectDescriptor>)dgvRepository.DataSource)[dgvRepository.CurrentRow.Index];
            
            if (selectedProject == null || selectedProject.Results == null || selectedProject.Results == String.Empty)
            {
                menuItemViewResults.Enabled = false;
                menuItemViewTabularResults.Enabled = false;
            }
            else
            {
                menuItemViewResults.Enabled = true;
                menuItemViewTabularResults.Enabled = true;
            }
        }

        #endregion

        #region Delete project delegates
        /// <summary>
        ///     The delegate for project deletion. The Id of the deleted project is returned (allows removal it 
        /// from list)
        /// </summary>
        /// <param name="projectDescriptor">the descriptor of the project to be deleted </param>
        /// <param name="userInfoData">user information</param>
        /// <returns></returns>
        private delegate string DeleteProjectDelegate(ProjectDescriptor projectDescriptor, UserInfoData userInfoData);

        /// <summary>
        ///     Callback for project deletion
        /// </summary>
        /// <param name="ar"></param>
        private void DeleteProjectCallBack (IAsyncResult ar)
        {
            try
            {
                string projectId = ((DeleteProjectDelegate)((AsyncResult)ar).AsyncDelegate).EndInvoke(ar);

                if (!IsDisposed && IsHandleCreated)
                {
                    BeginInvoke(new AfterDeleteProjectCompletedDelegate(AfterDeleteProjectCompleted), new object[] { true, projectId });
                }
            }
            catch (Exception ex)
            {
                BeginInvoke(new AfterDeleteProjectCompletedDelegate(AfterDeleteProjectCompleted), new object[] { false, null });
                new SolDevException("Cannot complete load process", ex);
            }
        }

        /// <summary>
        ///     The operation completion delegate, 
        /// </summary>
        /// <param name="success"></param>
        /// <param name="opResult"></param>
        private delegate void AfterDeleteProjectCompletedDelegate(bool success, string projectId);
        private void AfterDeleteProjectCompleted(bool success, string projectId)
        {
            propertyGrid1.SelectedObject = null;

            if (success == true)
            {
                if (projectId != null)
                {
                    if (DeleteProjectNotify != null)
                    {
                        DeleteProjectNotify(null, projectId);
                    }

                    List<ProjectDescriptor> projects = (List<ProjectDescriptor>)dgvRepository.DataSource;

                    for( int i = 0; i < dgvRepository.Rows.Count; i ++)
                    {
                        if(projects[i].Id.Equals(new Guid(projectId)))
                        {
                            projects.RemoveAt(i);
                            List<ProjectDescriptor> newProjects = new List<ProjectDescriptor>(projects);
                            dgvRepository.DataSource = newProjects;
                            break;
                        }
                    }
                }
                else
                {
                    new SolDevException("Could not delete repository project. No permitions ?");
                }
            }
        }
        #endregion

        #region Helper methods
        /// <summary>
        ///     Enable or disable form components when som operation is
        /// in progress.
        /// </summary>
        /// <param name="state"></param>
        private void EnableControls(bool state)
        {
            splitContainer.Enabled = state;
        }
        #endregion

    }
}

